#pragma once
#include <Rz/Object.h>
#include <Rz/ITypeWrapper.h>
#include <Rz/Collections/IEnumerable.h>
#include <Rz/IEquatable.h>

#include <map>

namespace Rz { namespace Collections {

#define _RZ_DICTIONARY_IENUM_SUBST IEnumerable<\
		T2,\
		Collections::TConstIteratorAdapter<typename std::map<T1, T2>::value_type, typename std::map<T1, T2>::const_iterator>,\
		Collections::TIteratorAdapter<typename std::map<T1, T2>::value_type, typename std::map<T1, T2>::iterator>\
	>

template <typename T1, typename T2>
class Dictionary :
	public Object,
	public _RZ_DICTIONARY_IENUM_SUBST,
	public IEquatable<Dictionary<T1, T2>>
{
	public:
		RZ_RTTI(Rz::Collections, Dictionary);
		RZ_RTTI_IMPLEMENTS(Object, _RZ_DICTIONARY_IENUM_SUBST);
		RZ_RTTI_TEMPLATES(NonObjectType<T1>, NonObjectType<T2>);
		RZ_RTTI_END;

		RZ_TYPEWRAPPER_IMPLEMENT(T1);

		typedef typename _RZ_DICTIONARY_IENUM_SUBST::ConstIterator ConstIterator;
		typedef typename _RZ_DICTIONARY_IENUM_SUBST::Iterator Iterator;

		Dictionary();
		Dictionary(const Dictionary<T1, T2>& dic);

		void Add(const std::pair<T1, T2>& pair);
		void Add(const T1& p1, const T2& p2);
		void Remove(const T1& p1);
		void Clear();

		const T2& operator [] (const T1& p1) const;
		T2& operator [] (const T1& p1);
		T2& GetMappedElement(const T1& p1);

		const T2& At(SizeType index) const;
		T2& At(SizeType index);

		SizeType GetCount() const;

		bool Contains(const T2& p2) const;

		// IEnumerable
 		virtual ConstIterator ConstBegin() const override;
 		virtual ConstIterator ConstEnd()   const override;
 
 		virtual Iterator Begin() override;
 		virtual Iterator End()   override;

		virtual bool Equals(const Dictionary<T1, T2>& r) const override;

		virtual bool operator == (const Dictionary<T1, T2>& r) const override;
		virtual bool operator != (const Dictionary<T1, T2>& r) const override;

	private:
		std::map<T1, T2> _map;
};

#undef _RZ_DICTIONARY_IENUM_SUBST

} }

#include "Dictionary.inl"
